home *** CD-ROM | disk | FTP | other *** search
/ CD Actual Thematic 7: Programming / CDAT7.iso / Share / Codigo / hh / rsource.exe / Heretic Source / Z_ZONE.C < prev   
Encoding:
C/C++ Source or Header  |  1996-02-13  |  8.4 KB  |  390 lines

  1. // Z_zone.c
  2.  
  3. #include <stdlib.h>
  4. #include "DoomDef.h"
  5.  
  6. /*
  7. ==============================================================================
  8.  
  9.                         ZONE MEMORY ALLOCATION
  10.  
  11. There is never any space between memblocks, and there will never be two
  12. contiguous free memblocks.
  13.  
  14. The rover can be left pointing at a non-empty block
  15.  
  16. It is of no value to free a cachable block, because it will get overwritten
  17. automatically if needed
  18.  
  19. ==============================================================================
  20. */
  21.  
  22. #define    ZONEID    0x1d4a11
  23.  
  24. typedef struct
  25. {
  26.     int        size;        // total bytes malloced, including header
  27.     memblock_t    blocklist;        // start / end cap for linked list
  28.     memblock_t    *rover;
  29. } memzone_t;
  30.  
  31. boolean MallocFailureOk;
  32. memzone_t *mainzone;
  33.  
  34. /*
  35. ========================
  36. =
  37. = Z_ClearZone
  38. =
  39. ========================
  40. */
  41.  
  42. void Z_ClearZone (memzone_t *zone)
  43. {
  44.     memblock_t    *block;
  45.     
  46. // set the entire zone to one free block
  47.  
  48.     zone->blocklist.next = zone->blocklist.prev = block =
  49.         (memblock_t *)( (byte *)zone + sizeof(memzone_t) );
  50.     zone->blocklist.user = (void *)zone;
  51.     zone->blocklist.tag = PU_STATIC;
  52.     zone->rover = block;
  53.     
  54.     block->prev = block->next = &zone->blocklist;
  55.     block->user = NULL;    // free block
  56.     block->size = zone->size - sizeof(memzone_t);
  57. }
  58.  
  59.  
  60. /*
  61. ========================
  62. =
  63. = Z_Init
  64. =
  65. ========================
  66. */
  67.  
  68. void Z_Init (void)
  69. {
  70.     memblock_t    *block;
  71.     int        size;
  72.  
  73.     MallocFailureOk = false;
  74.     mainzone = (memzone_t *)I_ZoneBase (&size);
  75.     mainzone->size = size;
  76.  
  77. // set the entire zone to one free block
  78.  
  79.     mainzone->blocklist.next = mainzone->blocklist.prev = block =
  80.         (memblock_t *)( (byte *)mainzone + sizeof(memzone_t) );
  81.     mainzone->blocklist.user = (void *)mainzone;
  82.     mainzone->blocklist.tag = PU_STATIC;
  83.     mainzone->rover = block;
  84.     
  85.     block->prev = block->next = &mainzone->blocklist;
  86.     block->user = NULL;    // free block
  87.     block->size = mainzone->size - sizeof(memzone_t);
  88. }
  89.  
  90.  
  91. /*
  92. ========================
  93. =
  94. = Z_Free
  95. =
  96. ========================
  97. */
  98.  
  99. void Z_Free (void *ptr)
  100. {
  101.     memblock_t    *block, *other;
  102.     
  103.     block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
  104.     if (block->id != ZONEID)
  105.         I_Error ("Z_Free: freed a pointer without ZONEID");
  106.         
  107.     if (block->user > (void **)0x100)    // smaller values are not pointers
  108.         *block->user = 0;        // clear the user's mark
  109.     block->user = NULL;    // mark as free
  110.     block->tag = 0;
  111.     block->id = 0;
  112.     
  113.     other = block->prev;
  114.     if (!other->user)
  115.     {    // merge with previous free block
  116.         other->size += block->size;
  117.         other->next = block->next;
  118.         other->next->prev = other;
  119.         if (block == mainzone->rover)
  120.             mainzone->rover = other;
  121.         block = other;
  122.     }
  123.     
  124.     other = block->next;
  125.     if (!other->user)
  126.     {    // merge the next free block onto the end
  127.         block->size += other->size;
  128.         block->next = other->next;
  129.         block->next->prev = block;
  130.         if (other == mainzone->rover)
  131.             mainzone->rover = block;
  132.     }
  133. }
  134.  
  135.  
  136. /*
  137. ========================
  138. =
  139. = Z_Malloc
  140. =
  141. = You can pass a NULL user if the tag is < PU_PURGELEVEL
  142. ========================
  143. */
  144.  
  145. #define MINFRAGMENT    64
  146.  
  147. void *Z_Malloc (int size, int tag, void *user)
  148. {
  149.     int        extra;
  150.     memblock_t    *start, *rover, *new, *base;
  151.  
  152. //
  153. // scan through the block list looking for the first free block
  154. // of sufficient size, throwing out any purgable blocks along the way
  155. //
  156.     size += sizeof(memblock_t);    // account for size of block header
  157.     
  158.     
  159. //
  160. // if there is a free block behind the rover, back up over them
  161. //
  162.     base = mainzone->rover;
  163.     if (!base->prev->user)
  164.         base = base->prev;
  165.     
  166.     rover = base;
  167.     start = base->prev;
  168.     
  169.     do
  170.     {
  171.         if(rover == start)
  172.         { // Scanned all the way around the list
  173.             if(MallocFailureOk == true)
  174.             {
  175.                 return NULL;
  176.             }
  177.             else
  178.             {
  179.                 I_Error("Z_Malloc: failed on allocation of %i bytes", size);
  180.             }
  181.         }
  182.         if (rover->user)
  183.         {
  184.             if (rover->tag < PU_PURGELEVEL)
  185.             // hit a block that can't be purged, so move base past it
  186.                 base = rover = rover->next;
  187.             else
  188.             {
  189.             // free the rover block (adding the size to base)
  190.                 base = base->prev;    // the rover can be the base block
  191.                 Z_Free ((byte *)rover+sizeof(memblock_t));
  192.                 base = base->next;
  193.                 rover = base->next;
  194.             }
  195.         }
  196.         else
  197.             rover = rover->next;
  198.     } while (base->user || base->size < size);
  199.     
  200. //
  201. // found a block big enough
  202. //
  203.     extra = base->size - size;
  204.     if (extra >  MINFRAGMENT)
  205.     {    // there will be a free fragment after the allocated block
  206.         new = (memblock_t *) ((byte *)base + size );
  207.         new->size = extra;
  208.         new->user = NULL;        // free block
  209.         new->tag = 0;
  210.         new->prev = base;
  211.         new->next = base->next;
  212.         new->next->prev = new;
  213.         base->next = new;
  214.         base->size = size;
  215.     }
  216.     
  217.     if (user)
  218.     {
  219.         base->user = user;            // mark as an in use block
  220.         *(void **)user = (void *) ((byte *)base + sizeof(memblock_t));
  221.     }
  222.     else
  223.     {
  224.         if (tag >= PU_PURGELEVEL)
  225.             I_Error ("Z_Malloc: an owner is required for purgable blocks");
  226.         base->user = (void *)2;        // mark as in use, but unowned    
  227.     }
  228.     base->tag = tag;
  229.     
  230.     mainzone->rover = base->next;    // next allocation will start looking here
  231.     
  232.     base->id = ZONEID;
  233.     return (void *) ((byte *)base + sizeof(memblock_t));
  234. }
  235.  
  236.  
  237. /*
  238. ========================
  239. =
  240. = Z_FreeTags
  241. =
  242. ========================
  243. */
  244.  
  245. void Z_FreeTags (int lowtag, int hightag)
  246. {
  247.     memblock_t    *block, *next;
  248.     
  249.     for (block = mainzone->blocklist.next ; block != &mainzone->blocklist 
  250.     ; block = next)
  251.     {
  252.         next = block->next;        // get link before freeing
  253.         if (!block->user)
  254.             continue;            // free block
  255.         if (block->tag >= lowtag && block->tag <= hightag)
  256.             Z_Free ( (byte *)block+sizeof(memblock_t));
  257.     }
  258. }
  259.  
  260. /*
  261. ========================
  262. =
  263. = Z_DumpHeap
  264. =
  265. ========================
  266. */
  267.  
  268. void Z_DumpHeap (int lowtag, int hightag)
  269. {
  270.     memblock_t    *block;
  271.     
  272.     printf ("zone size: %i  location: %p\n",mainzone->size,mainzone);
  273.     printf ("tag range: %i to %i\n",lowtag, hightag);
  274.     
  275.     for (block = mainzone->blocklist.next ; ; block = block->next)
  276.     {
  277.         if (block->tag >= lowtag && block->tag <= hightag)
  278.             printf ("block:%p    size:%7i    user:%p    tag:%3i\n",
  279.             block, block->size, block->user, block->tag);
  280.         
  281.         if (block->next == &mainzone->blocklist)
  282.             break;            // all blocks have been hit    
  283.         if ( (byte *)block + block->size != (byte *)block->next)
  284.             printf ("ERROR: block size does not touch the next block\n");
  285.         if ( block->next->prev != block)
  286.             printf ("ERROR: next block doesn't have proper back link\n");
  287.         if (!block->user && !block->next->user)
  288.             printf ("ERROR: two consecutive free blocks\n");
  289.     }
  290. }
  291.  
  292. /*
  293. ========================
  294. =
  295. = Z_FileDumpHeap
  296. =
  297. ========================
  298. */
  299.  
  300. void Z_FileDumpHeap (FILE *f)
  301. {
  302.     memblock_t    *block;
  303.     
  304.     fprintf (f,"zone size: %i  location: %p\n",mainzone->size,mainzone);
  305.     
  306.     for (block = mainzone->blocklist.next ; ; block = block->next)
  307.     {
  308.         fprintf (f,"block:%p    size:%7i    user:%p    tag:%3i\n",
  309.         block, block->size, block->user, block->tag);
  310.         
  311.         if (block->next == &mainzone->blocklist)
  312.             break;            // all blocks have been hit    
  313.         if ( (byte *)block + block->size != (byte *)block->next)
  314.             fprintf (f,"ERROR: block size does not touch the next block\n");
  315.         if ( block->next->prev != block)
  316.             fprintf (f,"ERROR: next block doesn't have proper back link\n");
  317.         if (!block->user && !block->next->user)
  318.             fprintf (f,"ERROR: two consecutive free blocks\n");
  319.     }
  320. }
  321.  
  322. /*
  323. ========================
  324. =
  325. = Z_CheckHeap
  326. =
  327. ========================
  328. */
  329.  
  330. void Z_CheckHeap (void)
  331. {
  332.     memblock_t    *block;
  333.     
  334.     for (block = mainzone->blocklist.next ; ; block = block->next)
  335.     {
  336.         if (block->next == &mainzone->blocklist)
  337.             break;            // all blocks have been hit    
  338.         if ( (byte *)block + block->size != (byte *)block->next)
  339.             I_Error ("Z_CheckHeap: block size does not touch the next block\n");
  340.         if ( block->next->prev != block)
  341.             I_Error ("Z_CheckHeap: next block doesn't have proper back link\n");
  342.         if (!block->user && !block->next->user)
  343.             I_Error ("Z_CheckHeap: two consecutive free blocks\n");
  344.     }
  345. }
  346.  
  347.  
  348. /*
  349. ========================
  350. =
  351. = Z_ChangeTag
  352. =
  353. ========================
  354. */
  355.  
  356. void Z_ChangeTag2 (void *ptr, int tag)
  357. {
  358.     memblock_t    *block;
  359.     
  360.     block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
  361.     if (block->id != ZONEID)
  362.         I_Error ("Z_ChangeTag: freed a pointer without ZONEID");
  363.     if (tag >= PU_PURGELEVEL && (unsigned)block->user < 0x100)
  364.         I_Error ("Z_ChangeTag: an owner is required for purgable blocks");
  365.     block->tag = tag;
  366. }
  367.  
  368.  
  369. /*
  370. ========================
  371. =
  372. = Z_FreeMemory
  373. =
  374. ========================
  375. */
  376.  
  377. int Z_FreeMemory (void)
  378. {
  379.     memblock_t    *block;
  380.     int            free;
  381.     
  382.     free = 0;
  383.     for (block = mainzone->blocklist.next ; block != &mainzone->blocklist 
  384.     ; block = block->next)
  385.         if (!block->user || block->tag >= PU_PURGELEVEL)
  386.             free += block->size;
  387.     return free;
  388. }
  389.  
  390.